﻿package BTChat;
import javax.bluetooth.*;
import javax.microedition.io.*;
import java.io.*;
import java.util.*;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;

public class BTChatBT implements Runnable, DiscoveryListener
{
    //<editor-fold defaultstate="collapsed" desc=" Pola klasy ">
    private LocalDevice Device;
    public ServiceRecord myHost;
    public RemoteDevice[] myHosts;
    private DiscoveryAgent szukaj;
    private ServiceRecord usluga;
    private StreamConnectionNotifier scn;
    private Vector wektor;
    private StreamConnection polaczenie = null;
    private BTChat parent;
    public Thread w;
    private static final int wersja = 0x3232;
    private static final UUID idserwera = new UUID("ABCDEF12345678998877665544332211", false);
    public Vector Devices;
    private UUID[] idklient;
    private int[] atrybuty;
    private boolean list;
    private message tekst;
    private Alert error;
    private boolean jestS = false;
    private boolean zakonczono = false;
    public boolean searchOnly;
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc=" Konstruktor BTChat() ">
    public BTChatBT(BTChat _parent)
    {
	parent = _parent;
	Devices = new Vector();
	idklient = new UUID[2];
	idklient[0] = new UUID(0x1101);
	idklient[1] = idserwera;
	atrybuty = new int[1];
	atrybuty[0] = wersja;
	w = new Thread(this);
	this.searchOnly = true;
	try
	{
	    Device = LocalDevice.getLocalDevice();
	    szukaj = Device.getDiscoveryAgent();
	}
	catch (Exception e)
	{
	    if(parent.debugeMode == true)
	    {
		this.error = new Alert("Błąd krytyczny", e.toString(), null,AlertType.ERROR);
		this.parent.display.setCurrent(error);
	    }
	}
	w.start();
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc=" Wątek nasłuchu ">
    public void startSerwer()
    {
	this.w = new Thread(this);
	this.searchOnly = false;
	this.w.start();
    }

    public synchronized void run()
    {
	if(searchOnly == true)
	{
	    try
	    {
		szukaj.startInquiry(DiscoveryAgent.GIAC,this);
		wait();
		this.szukajUslugi();
		this.searchOnly = false;
		this.parent.elements = this.getDevices();
		this.parent.searchFinished();
	    }
	    catch (Exception e)
	    {
		if(parent.debugeMode == true)
		{
		    this.error = new Alert("Błąd krytyczny", e.toString(), null,AlertType.ERROR);
		    this.parent.display.setCurrent(error);
		}
	    } 
	}
	else
	{
	    try
	    {
		wektor = new Vector();
		Device.setDiscoverable(DiscoveryAgent.GIAC);
		String url = "btspp://localhost:"+idserwera.toString() + ";name=chat;authorize=false";
		scn = (StreamConnectionNotifier)Connector.open(url, Connector.READ_WRITE);
		usluga = Device.getRecord(scn);
		DataElement parametr = new DataElement(DataElement.INT_1,1);
		usluga.setAttributeValue(wersja,parametr);
	    }
	    catch (Exception e)
	    {
		if(parent.debugeMode == true)
		{
		    this.error = new Alert("Błąd krytyczny", e.toString(), null,AlertType.ERROR);
		    this.parent.display.setCurrent(error);
		}
	    }
	    while (true)
	    {

		try 
		{
		    polaczenie = scn.acceptAndOpen();
		    myHosts = szukaj.retrieveDevices(DiscoveryAgent.CACHED);
		    for(int i =0; i< myHosts.length; i++)
		    {
			System.out.println(myHosts.toString());
		    }
		    this.odbierz(polaczenie);
		}
		catch (Exception e)
		{
		    if(parent.debugeMode == true)
		    {
			this.error = new Alert("Błąd krytyczny", e.toString(), null,AlertType.ERROR);
			this.parent.display.setCurrent(error);
		    }
		}
	    }
	}
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc=" Obsługa wyszukiwania ">
    public void deviceDiscovered(RemoteDevice urz, DeviceClass rodzaj)
    {
	if (Devices.indexOf(urz)==-1)
	{
	    Devices.addElement(urz);
	}
    }

    public void inquiryCompleted(int rodzaj)
    {
	if (rodzaj == DiscoveryListener.INQUIRY_COMPLETED)
	{
	    synchronized(this)
	    {
		notify();
		//System.out.println("cos jest");
	    }
	}
    }
    
    public void servicesDiscovered(int IDtransakcji, ServiceRecord[] uslugi)
    {
	if(myHost == null)
	{
	    for (int i=0; i < uslugi.length; i++)
	    {
		DataElement de = uslugi[i].getAttributeValue(wersja);
		uslugi[i].getConnectionURL(i, list);
		long parametr = de.getLong();
		if (parametr==1)
		{
		    jestS = true;
		    myHost = uslugi[i];
		}
	    }
	}
    }

    public void serviceSearchCompleted(int IDtransakcji, int kod)
    {
	if (jestS && !zakonczono)
	{
	    zakonczono = true;
	    synchronized(this)
	    {
		notify();
	    }
	}
    }

    public void szukajUslugi() throws Exception
    {
	for (int i=0;i<Devices.size();i++)
	{
	    RemoteDevice urz = (RemoteDevice)Devices.elementAt(i);
	    szukaj.searchServices(atrybuty,idklient,urz,this);
	    //System.out.println(Device.toString());
	}
    }
    
    public String[] getDevices()
    {
	String [] fDevices = new String[Devices.size()];
	RemoteDevice mDevice;
	for (int i=0; i < Devices.size(); i++)
	{
	    mDevice = (RemoteDevice) Devices.elementAt(i);
	    fDevices[i] = new String(mDevice.getBluetoothAddress());
	    try
	    {
		fDevices[i] = fDevices[i] + "(" + new String(mDevice.getFriendlyName(true)) + ")";
	    }
	    catch (Exception e)
	    {
		if(parent.debugeMode == true)
		{
		    this.error = new Alert("Błąd krytyczny", e.toString(), null,AlertType.ERROR);
		    this.parent.display.setCurrent(error);
		}
	    }
	}
	return fDevices;
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc=" Routing pakietów ">
    public void send(message wiad)
    {
	if(this.myHost != null)
	{
	    try
	    {
	    sender cos = new sender(wiad, (StreamConnection)Connector.open(this.myHost.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false)));
	    	    }
	    catch (Exception e)
	    {
		if(parent.debugeMode == true)
		{
		    this.error = new Alert("Błąd krytyczny", e.toString(), null,AlertType.ERROR);
		    this.parent.display.setCurrent(error);
		}
	    }
	}
	
	for(int i =0; i < myHosts.length; i++)
	{
	    try
	    {
		sender cos = new sender(wiad, (StreamConnection)Connector.open("btspp://" + myHosts[i].getBluetoothAddress()+":1;master=false;encrypt=false;authenticate=false"));
	    }
	    catch (Exception e)
	    {
		if(parent.debugeMode == true)
		{
		    this.error = new Alert("Błąd krytyczny", e.toString(), null,AlertType.ERROR);
		    this.parent.display.setCurrent(error);
		}
	    }
	}
    }

    private class sender implements Runnable
    {
        private Thread processorThread;
	private message tekst;
	private StreamConnection host;
	private Alert error;
        sender(message _tekst, StreamConnection _host) 
	{
	    host = _host;
	    
	    this.tekst = _tekst;
            processorThread = new Thread(this);
            processorThread.start();
        }

        public void run() 
	{
	    try
	    {
		OutputStream wyj = host.openOutputStream();
		byte dlugosc = (byte)tekst.nick.length();
		wyj.write(dlugosc);
		wyj.write(tekst.nick.getBytes("ISO-8859-1"));
		wyj.flush();
		dlugosc = (byte)tekst.text.length();
		wyj.write(dlugosc);
		wyj.write(tekst.text.getBytes("ISO-8859-1"));
		wyj.flush();
		wyj.close();
	    }
	     catch (Exception e)
	    {
		if(parent.debugeMode == true)
		{
		    this.error = new Alert("Błąd krytyczny", e.toString(), null,AlertType.ERROR);
		}
	    }
        }
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc=" Destruktor ">
    public void zamknij()
    {
	if (scn!=null)
	{
	    try
	    {
		if (polaczenie!=null)
		    polaczenie.close();
		scn.close();
	    } 
	    catch (Exception e)
	    {
		if(parent.debugeMode == true)
		    this.error = new Alert("Błąd krytyczny", e.toString(), null,AlertType.ERROR);
	    }
	}
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc=" Odbieranie pakietów ">
    public String odbierz(StreamConnection connection) throws Exception
    {
	InputStream wej = connection.openInputStream();
	int dlugosc = wej.read();
	byte[] bufor = new byte[dlugosc];
	int licznik = 0;
	while (licznik<dlugosc)
	{
	    int liczba = wej.read(bufor,licznik,dlugosc-licznik);
	    licznik += liczba;
	}
	String nick = new String(bufor,"ISO-8859-1");
	dlugosc = wej.read();
	bufor = new byte[dlugosc];
	licznik = 0;
	while (licznik<dlugosc)
	{
	    int liczba = wej.read(bufor,licznik,dlugosc-licznik);
	    licznik += liczba;
	}
	String mes = new String(bufor,"ISO-8859-1");
	message wiad = new message(mes, nick, parent.time);
	parent.form.append(wiad.show());
	wej.close();
	return nick;
    }
    //</editor-fold>
}
